package MtG.publicClass;

import java.util.Iterator;
import java.io.Serializable;

import MtG.publicClass.messages.Attack;
import MtG.publicClass.messages.EndTurn;


/**
 * Game.java holds the basic methods that the game is based on.
 * @author Marek Sirp
 * @author Jaan Sepp
 */
public class Game implements Serializable{
	
	/**
	 * Determines if a de-serialized file is compatible with this class.
	 */
	private static final long serialVersionUID = -7480478968413184704L;	
	/**
	 * Maximum amount of cards, what can be in hand
	 */
	private final int MAXCARDSINHAND = 7;
	/**
	 * Field that holds the reference to one of the two active players (player1).
	 */
	private Player player1 = null;
	/**
	 * Field that holds the reference to one of the two active players (player2).
	 */
	private Player player2 = null;
	/**
	 * Field that holds the reference to which players turn it currently is.
	 */
	private Player whoseTurn;	
	/**
	 * Waiting time before player1 trying to connect to server again;
	 */
	private final int WAITINGTINE=1*1000;
	Message messageObject;
	/**
	 * the most important method that describes all the processes that are carried out during one turn of a player.
	 * @return retrieves the reference to this game.
	 */
	public void move(){
		
		int damagaDealt = 0;
		int lifeLost = 0;
		int deadCards = 0;
		
		Player defender;
		int lastMonsterDefence = 0;
		if(getWhoseTurn().getSecurityNumber().equals(player1.getSecurityNumber())){
			System.out.println("player1 " + player1.getName() + " " + player1.getSecurityNumber());
			defender = player2;
		} else {
			System.out.println("player2 " + player2.getName() + " " + player2.getSecurityNumber());
			defender = player1;
		}
		whoseTurn.drawCardFromDeck(1);
		whoseTurn.setInitMana(whoseTurn.getMaxMana());
		whoseTurn.setManaPlaced(false);
		
		Iterator<Card> attackerIterator = whoseTurn.getPlayersCardsInPlay().iterator();
		Iterator<Card> defenderIterator = defender.getPlayersCardsInPlay().iterator();		
		
		Card defenderCard = null;
		if(defenderIterator.hasNext()){
			defenderCard = defenderIterator.next();		
			lastMonsterDefence = defenderCard.getDefenceValue();
		}
		
		while(attackerIterator.hasNext()){		
			Card attackerCard = attackerIterator.next();
			while(attackerCard.isUseThisTurn()){
				if(defenderCard != null && !defenderCard.isDead()){
						int monsterDefence = defenderCard.getDefenceValue();
						monsterDefence -= attackerCard.getAttackValue();
						damagaDealt += attackerCard.getAttackValue();
						if(monsterDefence <= 0){
							deadCards++;
							defenderCard.setDead(true);
							if(defenderIterator.hasNext()){
								defenderCard = (Card)defenderIterator.next();
								lastMonsterDefence = defenderCard.getDefenceValue();
							}
						} else {
							if(attackerIterator.hasNext()){
								defenderCard.setDefenceValue(monsterDefence);								
							} else {
								defenderCard.setDefenceValue(lastMonsterDefence);
								attackerCard.useOnthisturn(false);
							}
							
						}
						attackerCard.useOnthisturn(false);
						}					
			if(attackerCard.isUseThisTurn() && attackerCard.isUseable()){
				lifeLost += attackerCard.getAttackValue();
				damagaDealt += attackerCard.getAttackValue();
				defender.decreaseHitPoints(attackerCard.getAttackValue());
			}		
			attackerCard.useOnthisturn(false);
		}
			attackerCard.setUseable(true);
		}
		for(int i = 0 ; i< defender.getPlayersCardsInPlay().size(); i++){
			if(defender.getPlayersCardsInPlay().get(i).isDead()){				
				defender.getPlayersCardsInPlay().remove(i);
			}
		}
		System.out.println("switch players");
		setMessage(whoseTurn, defender, damagaDealt, lifeLost, deadCards);
		update(defender);		
	}
	
	/**
	 * This method adds the first client as Player1, second as Player2 and the rest as spectators in this game.
	 * @param player the player that will be added in the role of spectator or an actual player.
	 */
	public void addPlayer(Player player){
		player.drawCardFromDeck(MAXCARDSINHAND);
		if(player1 == null){	
			player1 = player;
			player1.setSpectator(false);
		} else if(player2 == null){
			player2 = player;

			player2.setSpectator(false);
		}
	}
	
	private void setMessage(Player whoseTurn, Player defender, int damagaDealt, int lifeLost, int deadCards){
		if(damagaDealt == 0){
			this.messageObject = new EndTurn(defender);
		} else {
			this.messageObject = new Attack(whoseTurn, defender, damagaDealt, lifeLost, deadCards);
		}
	}
	
	
	/**
	 * This method makes the first player that joined to wait until second player joins the game.
	 * @throws InterruptedException when the waiting of the first player is suddenly haulted.
	 */
	public void waitingForPlayers() throws InterruptedException{
		if(player2 == null){			
			synchronized (player1) {
				whoseTurn = player1;
				player1.wait(WAITINGTINE);
				if(player2==null){
					whoseTurn = null;
					player1 = null;
				}
			}
		} else {
			synchronized (player1) {
				player1.notify();
				System.out.println(player1.getName() + " " + player2.getName());
			}
		}
		
	}
	
	/**
	 * function for checking, if game is started or not
	 * @return - true, if game is started else false.
	 */
	public boolean isStarted(){
		if(player1 != null && player2 != null){
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * This method resets the game by resetting all the players and 
	 * whoseTurn.
	 */
	public void reset(){
		player1 = null;
		player2 = null;
		whoseTurn = null;
	}
	
	/**
	 * 
	 * @param player
	 */
	public Game update(Player player){
		if(player1.getSecurityNumber().equals(player.getSecurityNumber())){
			player1 = player;
		} else {
			player2 = player;
		}
		whoseTurn = player;
		return this;
	}

	
	/**
	 * @param player player whose securityNumber will be checked
	 * @return actual player or observer.
	 */
	public Player updatePlayer(Player player){
		if(player.getSecurityNumber().equals(player1.getSecurityNumber())){
			return player1;
		} else if (player.getSecurityNumber().equals(player2.getSecurityNumber())){
			return player2;
		} else {
			return player;
		}
	}
	
	/**
	 * @param player checks whose turn it currently is.
	 * @return the reference to the player whose turn it is.
	 */
	public String playerRoll(Player player){
		if(player1.getSecurityNumber().equals(player.getSecurityNumber())){
			return "player1";
		} else {
			return "player2";
		}
		
	}
	
	/**
	 * @return retrieve the player1.
	 */
	public Player getPlayer1(){
		return player1;
	}
	
	/**
	 * @return retrieve the player2.
	 */
	public Player getPlayer2(){
		return player2;
	}
	
	/**
	 * @return retrieve the player whose turn it currently is.
	 */
	public Player getWhoseTurn(){
		return whoseTurn;
	}
	
	/**
	 * @param player player that will be checked.
	 * @return true if its currently this players turn and false if not.
	 */
	public boolean onTurn(Player player){
		if(player.getSecurityNumber().equals(getWhoseTurn().getSecurityNumber())){
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Check, if game has the winner.
	 * @return true, if game has the winner else false.
	 */
	public boolean isWinner(){
		if((player1.getCurrentHitPoints() <= 0) || player2.getCurrentHitPoints() <= 0){
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 	 * @return player, who is the winner.
	 */
	public Player whoIsWinner(){
		if(player1.getCurrentHitPoints() <= 0){
			return player2;
		} else {
			return player1;
		}
	}
	
	/**
	 * @return the messageObject of this game.
	 */
	public Message getMessage(){
		Message message = this.messageObject;
		messageObject = null;
		return message;		
	}
}
